﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Serialization;

namespace Derrick.Web
{
    public class WebSocketServer : Server
    {

        protected List<WebSocketClient> clients = null;

        private WebSocketConfig config;

        public WebSocketServer(WebSocketConfig c)
            : base(Dns.GetHostEntry(IPAddress.Parse(c.BindTo)).AddressList[0], c.Port, c.Authentication)
        {
            config = c;
            clients = new List<WebSocketClient>();
            
        }

        public override Response HandleRequest(Request request, DateTime lastUpdate, Client cometClient)
        {
            if (_traceSwitch == null)
            {
                _traceSwitch = new TraceSwitch("TraceLevelSwitch", "Comet Tracing");
            }

            ///TO DO: add in method to send response in JSON
            ///Derrick Lau - Feb. 3, 2012
            //Console.WriteLine("SIServer HandleRequest(). " + request.Url);
            Trace.WriteLine("Web Socket Server HandleRequest(). " + request.Url);

            //Console.WriteLine("---");
            Trace.WriteLine("---");
            //Console.WriteLine("\""+request.Body+"\"");
            Trace.WriteLine("\"" + request.Body + "\"");
            //Console.WriteLine("---");
            Trace.WriteLine("---");

            Trace.WriteLineIf(_traceSwitch.TraceInfo, "Inside Web Socket Server.HandleRequest()...");

            try
            {

                #region Process HTTP message as XML
                //Picks up message from HTTP:
                XmlSerializer s = new XmlSerializer(typeof(XmlRequest));

                MemoryStream mem = new MemoryStream();
                mem.Write(System.Text.Encoding.ASCII.GetBytes(request.Body), 0, request.Body.Length);
                mem.Seek(0, 0);

                //Loads message into object for processing.
                XmlRequest data = (XmlRequest)s.Deserialize(mem);
                #endregion Process HTTP message as XML

                #region Process HTTP message as JSON




                #endregion Process HTTP message as JSON

                string responseMsg = String.Empty;

                MessageFormat responseFormat;

                if (request.Headers["Content-Type"].Contains("json"))
                {
                    responseFormat = MessageFormat.json;
                }
                else if (request.Headers["Content-Type"].Contains("xml"))
                {
                    responseFormat = MessageFormat.xml;
                }
                else
                {
                    responseFormat = MessageFormat.text;
                }

                return Response.GetHtmlResponse(responseMsg, QueueMessage.Instance.LastUpdated, responseFormat);

            }
            catch (Exception ex)
            {
                Console.WriteLine("Error parsing xml: " + ex.Message);
                Trace.WriteLineIf(_traceSwitch.TraceError, "Inside Web Socket Server.HandleRequest().  Exception thrown: " + ex.ToString());
                Trace.Flush();
                return Response.GetHtmlResponse("Error parsing xml: " + ex.Message, QueueMessage.Instance.LastUpdated, MessageFormat.text);
            }
        }

        public override void Loop()
        {
            //base.Loop();

            try
            {
                //List<Client> clients = new List<Client>();

                while (true)
                {


                    TcpClient client = null;

                    bool isServerStopped = false;
                    _listenerMutex.WaitOne();
                    isServerStopped = _isListenerShutDown;
                    _listenerMutex.ReleaseMutex();

                    if (!isServerStopped)
                    {
                        client = listener.AcceptTcpClient();
                    }
                    else
                    {
                        continue;
                    }

                    Trace.WriteLineIf(_traceSwitch.TraceInfo, "Web Socket Server: TCP client accepted.", "Web Socket Server");

                    bool addClientFlag = true;

                    WebSocketClient dc = new WebSocketClient(client, this, authconfig, _currentClientId);
                    _currentClientId++;

                    for (int i = 0; i < clients.Count; i++)
                    {

                        if (!clients[i].IsLive || !clients[i].TCPClient.Connected)
                        {
                            clients[i].CleanUp();
                            clients.RemoveAt(i);
                        }

                        if (dc.TCPClient == clients[i].TCPClient)
                        {
                            lock (_lockObj)
                            {
                                addClientFlag = false;
                                //break;
                            }
                        }


                    }

                    if (addClientFlag)
                    {
                        lock (_lockObj)
                        {
                            clients.Add(dc);
                        }
                    }

                    Trace.WriteLineIf(_traceSwitch.TraceInfo, "Web Socket Server: Number of TCP clients: " + clients.Count);


                }
            }
            catch (Exception ex)
            {
                //EventLog.WriteEntry("Derrick COMET", ex.ToString(), EventLogEntryType.Error);
                Trace.WriteLineIf(_traceSwitch.TraceError, ex.ToString(), "Web Socket Server");
            }


        }

        

    }
}
